package db;

import ptolemy.kernel.*;

import java.util.*;
import java.net.URL;
import java.io.*;

import org.xml.sax.helpers.DefaultHandler;

import MoC.*;

//////////////////////////////////////////////////////////////////////////
//// CompositeActorInfo
/**

    Representa as informacoes de um nivel da hierarquia, isto e, um 
    ator hierarquico.

@author Ivan Jeukens
@version v 0.1 24/01/2002
*/
public class CompositeActorInfo extends dbInfo {

    /* Usado quando estou criando os dados de um ator composite pela
    primeira vez, no VerifierEffigy */
    public CompositeActorInfo(CompositeEntity entity,
            DataBase compositeActorDB,
            DataBase atomicActorDB,
            DataBase classDB,
            DataBase classDataDB) {
        _actorClass = entity.getClass();
        _entity = entity;
        _name = entity.getFullName();

        //_compositeActorsMap = new HashMap();

        _containedCompositeInfo = new LinkedList();
        _containedAtomicInfo = new LinkedList();

        _atomicActorDB = atomicActorDB;
        _classDB = classDB;
        _classDataDB = classDataDB;
        _compositeActorDB = compositeActorDB;

        _build();

        _result = new CompositeActorResult(this);
    }

    ///////////////////////////////////////////////////////////////////
    ////                        public methods                     ////

    public AtomicActorInfo getAtomicActorInfo(String name) {
        return (AtomicActorInfo) _atomicActorDB.get(name);
    }

    public Iterator atomicActorsIterator() {
        return _containedAtomicInfo.iterator();
    }

    public Iterator compositeActorsIterator() {
        return _containedCompositeInfo.iterator();
    }

    public int compositeActorsSize() {
        return _containedCompositeInfo.size();
    }

    public CompositeActorInfo getCompositeActorInfo(String name) {
        return (CompositeActorInfo) _compositeActorDB.get(name);
    }

    public void debug(String basepath) {
        String name = null;
        try {
            // Salva o arquivo que contem o basepath do primeiro composite
            File f = new File(_TEMP_DIR + "fgviewBasepath");
            f.createNewFile();
            FileOutputStream fo = new FileOutputStream(f);
            DataOutputStream ps = new DataOutputStream(fo);
            ps.writeUTF(basepath);
            fo.close();

            f = new File(_TEMP_DIR + basepath + "/");
            f.mkdirs();
            
            // Arquivo contendo o nome, logo o diretorio, de cada composite
            f = new File(_TEMP_DIR + basepath + "/composite");
            f.createNewFile();
            fo = new FileOutputStream(f);
            ps = new DataOutputStream(fo);

            ps.writeUTF(_name);
            fo.close();

            name = new String(_TEMP_DIR + basepath + "/" + 
                _name + "/");
            f = new File(name);
            f.mkdirs();

            File cfile = new File(name + "/actors");
            cfile.createNewFile();
            fo = new FileOutputStream(cfile);
            ps = new DataOutputStream(fo);

            HashMap collect = new HashMap();
            getAllClassInfo(collect);
            Iterator ite = collect.keySet().iterator();
            while(ite.hasNext()) {
                ClassInfo info = (ClassInfo) ite.next();
                ps.writeUTF(info.getName());
                info.debug(name);
            }
            fo.close();
        }
        catch(IOException ex) {
            System.out.println(ex);
        }
    }

    public CompositeActorResult getResult() {
        return _result;
    }

    // Retorna todos os atomic info, independente do nivel de hierarquia
    public void getAllAtomicInfo(HashMap ret) {
        for(int i = 0;i < _containedAtomicInfo.size();i++) {
            AtomicActorInfo ainfo = (AtomicActorInfo) _containedAtomicInfo.get(i);
            if(!ret.containsKey(ainfo)) {
                ret.put(ainfo, null);
            }
        }
        for(int i = 0;i < _containedCompositeInfo.size();i++) {
            CompositeActorInfo cinfo =
                (CompositeActorInfo) _containedCompositeInfo.get(i);
            cinfo.getAllAtomicInfo(ret);
        }
    }

    public void getAllClassInfo(HashMap ret) {
        for(int i = 0;i < _containedAtomicInfo.size();i++) {
            AtomicActorInfo ainfo = (AtomicActorInfo) _containedAtomicInfo.get(i);
            ClassInfo cinfo = ainfo.getClassInfo();
            if(!ret.containsKey(cinfo)) {
                ret.put(cinfo, null);
            }
        }
        for(int i = 0;i < _containedCompositeInfo.size();i++) {
            CompositeActorInfo cinfo =
                (CompositeActorInfo) _containedCompositeInfo.get(i);
            cinfo.getAllClassInfo(ret);
        }
    }

    public CompositeEntity getEntity() {
        return _entity;
    }
    
    ///////////////////////////////////////////////////////////////////
    ////                        private methods                    ////

    private void _build() {
        List entities = _entity.entityList();
        for(int i = 0;i < entities.size();i++) {
            Entity e = (Entity) entities.get(i);

            if(!(e instanceof CompositeEntity)) {
                // Acha na database ou cria
                AtomicActorInfo ainfo = _analyzeActor((ComponentEntity)e);
                if(!_containedAtomicInfo.contains(ainfo)) {
                    _containedAtomicInfo.add(ainfo);
                }
            }
            else {
                CompositeEntity ceactor = (CompositeEntity) e;
                CompositeActorInfo info = null;
                String cname = ceactor.getFullName();

                // Como e possivel saber se duas topologias sao iguais ou nao?
                // estou pegando o nome do ator, ai todas sao diferentes...

                if(_compositeActorDB.contains(cname)) {
                    info = (CompositeActorInfo) _compositeActorDB.getInfo(cname);
                }
                else {
                    info = new CompositeActorInfo(ceactor, _compositeActorDB,
                        _atomicActorDB, _classDB, _classDataDB);
                    _compositeActorDB.add(info);
                }

                if(!_containedCompositeInfo.contains(info)) {
                    _containedCompositeInfo.add(info);
                }
            }
        }
    }

    private AtomicActorInfo _analyzeActor(ComponentEntity ce) {
        // String name = ob.getClass().getName();
        String name = ce.getFullName();
        AtomicActorInfo af = null;
        if(!_atomicActorDB.contains(name)) {
            af = new AtomicActorInfo(_classDB, _classDataDB, ce);
            _atomicActorDB.add(af);
        }
        else {
            af = (AtomicActorInfo) _atomicActorDB.getInfo(name);
        }

        return af;
    }

    ///////////////////////////////////////////////////////////////////
    ////                        private variables                  ////

    private CompositeEntity _entity;

    private Class _actorClass;

    // Uma lista das compositeActorInfo dos atores composite desse
    // nivel de hierarquia.
    private LinkedList _containedCompositeInfo;
    private LinkedList _containedAtomicInfo;

    private CompositeActorResult _result;

    private DataBase _compositeActorDB;
    private DataBase _atomicActorDB;
    private DataBase _classDB;
    private DataBase _classDataDB;

    private URL _url;
    
    private static final String _TEMP_DIR = "/home/ivan/temp/";

}
